package org.ztest.invoke;

import java.lang.invoke.MethodHandle;
import java.lang.invoke.MethodHandles;
import java.lang.invoke.MethodHandles.Lookup;
import java.lang.invoke.MethodType;
import java.lang.reflect.Method;

public class MethodHandleTest2 implements Runnable
{
	private String fieldStr;
	
	private static int fieldInt;
	
	Lookup lookup()
	{
		return MethodHandles.lookup();
	}
	
	public void test() throws Throwable
	{
		MethodHandle mh = lookup().findSpecial(MethodHandleTest2.class, "run", MethodType.methodType(void.class), MethodHandleTest2.class);
		// 实例invoke方法的第一个参数必须为调用者自身
		mh.invoke(this);
		
		MethodHandle mh2 = lookup().findSpecial(MethodHandleTest2.class, "run", MethodType.methodType(void.class, int.class), MethodHandleTest2.class);
		mh2.invoke(this, 1);
		
		MethodHandle mh22 = lookup().findSpecial(MethodHandleTest2.class, "runPrivate", MethodType.methodType(void.class), MethodHandleTest2.class);
		mh22.invoke(this);
		
		MethodHandle mh23 = lookup().findStatic(MethodHandleTest2.class, "run", MethodType.methodType(void.class, int.class, int.class));
		// 静态invoke方法只需传递函数调用参数，无参数则不填
		mh23.invoke(1, 2);
		
		MethodHandle mh24 = lookup().findStatic(MethodHandleTest2.class, "run2", MethodType.methodType(void.class));
		mh24.invoke();
		
		MethodHandle mh3 = lookup().findVirtual(MethodHandleTest2.class, "run", MethodType.methodType(void.class));
		mh3.invoke(this);
		
		Model model = new Model();
		MethodHandle mh4 = lookup().findVirtual(Model.class, "run", MethodType.methodType(void.class));
		mh4.invoke(model);
		
		MethodHandle mh43 = lookup().findStatic(Model.class, "run2", MethodType.methodType(void.class));
		mh43.invoke();
		
		// 访问外部类的方法失败
//		MethodHandle mh42 = lookup().in(Model.class).findSpecial(Model.class, "run", MethodType.methodType(void.class), Model.class);
		// 可以先获取Method然后转换为MethodHandle间接访问外部类的方法
		Method method = Model.class.getDeclaredMethod("run");
		MethodHandle mh42 = lookup().unreflect(method);
		mh42.invoke(model);
		
		// 字段 Getter\Setter
		MethodHandle fieldMh = lookup().findGetter(MethodHandleTest2.class, "fieldStr", String.class);
		System.out.println(fieldMh.invoke(this));
		MethodHandle fieldMh2 = lookup().findSetter(MethodHandleTest2.class, "fieldStr", String.class);
		fieldMh2.invoke(this, "This is new fieldStr value");
		System.out.println(this.fieldStr);
		
		// 静态字段Getter\Setter
		MethodHandle fieldMh3 = lookup().findStaticGetter(MethodHandleTest2.class, "fieldInt", int.class);
		System.out.println(fieldMh3.invoke());
		MethodHandle fieldMh4 = lookup().findStaticSetter(MethodHandleTest2.class, "fieldInt", int.class);
		fieldMh4.invoke(9527);
		System.out.println(fieldInt);
	}
	
	public static void run(int arg1, int arg2)
	{
		System.out.println("This is runStatic");
	}
	
	public static void run2()
	{
		System.out.println("This is runStatic2");
	}
	
	@Override
	public void run()
	{
		System.out.println("This is run");
	}
	
	public void run(int arg)
	{
		System.out.println("This is run with arg");
	}
	
	public void runSelf()
	{
		System.out.println("This is runSelf");
	}
	
	@SuppressWarnings("unused")
	private void runPrivate()
	{
		System.out.println("This is runPrivate");
	}
}
